/*
 * Dcm_UDS0x2C.c
 *
 *  Created on: 2018-8-23
 *      Author: tao.yu
 */

#include "UDS.h"


/****************************************************************
         UDS:DynamicallyDefineDataIdentifier  (2C hex) service
 ***************************************************************/
#if(STD_ON == DCM_UDS_SERVICE0X2C_ENABLED)

#define  DCM_START_SEC_VAR_NOINIT_UNSPECIFIED
#include "Dcm_MemMap.h"
VAR(Dcm_DDDidTypes, DCM_VAR_NOINIT) Dcm_DDDid[DCM_DSP_DDDID_MAX_NUMBER];
#define  DCM_STOP_SEC_VAR_NOINIT_UNSPECIFIED
#include "Dcm_MemMap.h"

/***************************/
#if(STD_ON == DCM_DSP_DID_FUNC_ENABLED)
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static Std_ReturnType  DspInternalUDS0x2C_DidCheck(
        uint16 RecDid,
        P2VAR(uint8, AUTOMATIC, AUTOMATIC)pDidCfgIndex,
        P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, AUTOMATIC)pNrc)
{
    uint8     Index;
    boolean   Flag = FALSE;
    Std_ReturnType  ret = E_NOT_OK;

    if ((RecDid > 0xF200u) && (RecDid < 0xF3FFu))
    {
        /*find the corresponding DID in configuration*/
        for (Index = 0; (Index < Dcm_DspCfg.DcmDspDidNum) && (FALSE == Flag); Index++)
        {
            /*single did check*/
            if ((RecDid == Dcm_DspCfg.pDcmDspDid[Index].DcmDspDidId)
                    && (TRUE == Dcm_DspCfg.pDcmDspDid[Index].DcmDspDidUsed)
            && (Dcm_DspCfg.pDcmDspDidInfo[Dcm_DspCfg.pDcmDspDid[Index].DcmDspDidInfoIndex].
                    DcmDspDidDynamicallyDefined == TRUE)
            && (Dcm_DspCfg.pDcmDspDidInfo[Dcm_DspCfg.pDcmDspDid[Index].DcmDspDidInfoIndex].
                    DcmDspDDDIDMaxElements > 0u))
            {
                Flag = TRUE;
                (*pDidCfgIndex) = Index;
                ret = E_OK;
            }
        }
    }
    if (E_NOT_OK == ret)
    {
        /*if not found,send NRC 0x31*/
        (*pNrc) = DCM_E_REQUESTOUTOFRANGE;
    }

    return(ret);
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"
#endif


/***************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_Uds0x2CServiceConditionCheck(
        uint8 ProtocolCtrlId,
        P2VAR(uint8, AUTOMATIC, AUTOMATIC)MsgCtrlId)
{
    Std_ReturnType ret;

    /*************************************************/
    /*if the required protocol is
     *  configured,get the index of runtime datum*/
    *MsgCtrlId = Dcm_ProtocolCtrl[ProtocolCtrlId].MsgCtrlIndex;

    /*************************************************/
    #if(STD_ON == DCM_SESSION_FUNC_ENABLED)
    /*session check,check whether the current
     *  session supports the request service*/
    ret = DsdInternal_SesCheck(ProtocolCtrlId,
            SID_DYNAMICALLY_DEFINE_DATA_IDENTIFER);
    if(E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-073[DCM211]****/
        /*the current session does not support
         *  the request service,send NRC = 0x7F*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    #endif

    /*************************************************/
    #if(STD_ON == DCM_SECURITY_FUNC_ENABLED)
    /*security check,check whether the current
     * security supports the request service*/
    ret = DsdInternal_SecurityCheck(ProtocolCtrlId,
            SID_DYNAMICALLY_DEFINE_DATA_IDENTIFER);
    if (E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-074[DCM217]****/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SECURITYACCESSDENIED); /*NRC = 0x33*/
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    #endif

    /*check the massage length*/
    if (Dcm_MsgCtrl[*MsgCtrlId].MsgContext.ReqDataLen
            < DCM_UDS0X2C_REQ_DATA_MINLENGTH)
    {
        /*the length of massage is not correct,send NRC 0x13*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    return E_OK;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

/***************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
FUNC(Std_ReturnType, DCM_CODE)Dcm_UDS0x2C(
        Dcm_OpStatusType OpStatus,
        uint8  ProtocolCtrlId,
        P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_VAR) ErrorCode)
{
#if(STD_ON == DCM_DSP_DID_FUNC_ENABLED)
    uint16    RecDid;
    uint16    Offset;
    uint8     DidCfgIndex;
    uint8     iloop;
    uint8     index;
    uint8     Cnt;
    uint8     TxChannelCtrlIndex;
    uint8     TxChannelCfgIndex;
    uint32 MemoryAddress;
    uint32 Memorysize;
#endif
    uint8     MsgCtrlId;
    Std_ReturnType ret;
    uint8     Subfunction;
    boolean   Find = FALSE;
    uint8 addressAndLengthFormatIdentifier;
    uint8     memoryAddressByteLength;
    uint8     memorySizeByteLength;
    uint8     RequestNum;

    /*************************************************/
    ret = Dcm_Uds0x2CServiceConditionCheck(ProtocolCtrlId, &MsgCtrlId);
    if(E_OK != ret)
    {
        return ret;
    }

    Subfunction = Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[1u];

    if (Subfunction == DCM_UDS0X2C_01_DDBYDID)
    {
        /*check the massage length*/
        if ((Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen % 4u) != 0u)
        {
            /*the length of massage is not correct,send NRC 0x13*/
            (void)DsdInternal_SetNrc(ProtocolCtrlId,
                    DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
            DsdInternal_ProcessingDone(ProtocolCtrlId);
            return E_NOT_OK;
        }
        RequestNum = (uint8)((Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen >> 2u) - 1UL);
    }
    else if (Subfunction == DCM_UDS0X2C_02_DDBYMEMORY)
    {
        addressAndLengthFormatIdentifier = Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[4u];
        memoryAddressByteLength = addressAndLengthFormatIdentifier & 0x0Fu ;
        memorySizeByteLength = (addressAndLengthFormatIdentifier & 0xF0u) >> 4u;
        /*check the massage length*/
        if (((Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen - 5UL)
                % ((uint32)((uint32)memorySizeByteLength + memoryAddressByteLength))) != 0UL)
        {
            /*the length of massage is not correct,send NRC 0x13*/
            (void)DsdInternal_SetNrc(ProtocolCtrlId,
                    DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
            DsdInternal_ProcessingDone(ProtocolCtrlId);
            return E_NOT_OK;
        }
        RequestNum = (uint8)((uint8)(Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen - 5u)
                / (memorySizeByteLength + memoryAddressByteLength));
    }
    else if (Subfunction == DCM_UDS0X2C_03_CLEARDDDID)
    {
        /*check the massage length*/
        if (Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen
                != DCM_UDS0X2C_REQ_DATA_MINLENGTH)
        {
            /*the length of massage is not correct,send NRC 0x13*/
            (void)DsdInternal_SetNrc(ProtocolCtrlId,
                    DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
            DsdInternal_ProcessingDone(ProtocolCtrlId);
            return E_NOT_OK;
        }
    }
    else
    {
        /*the sub-function of massage is not correct,send NRC 0x12*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_SUBFUNCTIONNOTSUPPORTED);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

#if (STD_OFF == DCM_DSP_DID_FUNC_ENABLED)
    /*NRC 0x31:request out of range*/
    (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_REQUESTOUTOFRANGE);
    DsdInternal_ProcessingDone(ProtocolCtrlId);
    return E_NOT_OK;

#else
    /**************************************************/
    /*get the required DID from request message*/
    RecDid = (uint16)((uint16)((uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[2]) << 8u)\
            |((uint16) Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[3]);

    /*Determine if the DID is configured*/
    ret = DspInternalUDS0x2C_DidCheck(RecDid,
                                     &DidCfgIndex,
                                     ErrorCode);
    if(E_NOT_OK == ret)
    {
        /*if not found,send NRC 0x31*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,*ErrorCode);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return  E_NOT_OK;
    }

    for (iloop = 0; (iloop < DCM_DSP_DDDID_MAX_NUMBER) && (Find == FALSE); iloop++)
    {
        if (RecDid == Dcm_DDDid[iloop].DDDid)
        {
            Find = TRUE;
        }
    }

    if (Find == FALSE)
    {
        for (iloop = 0; (iloop < DCM_DSP_DDDID_MAX_NUMBER) && (Find == FALSE); iloop++)
        {
            if (0u == Dcm_DDDid[iloop].DDDid)
            {
                Find = TRUE;
            }
        }

        if (Find == TRUE)
        {
            Dcm_DDDid[iloop].DDDid = RecDid;
            if(Dcm_DDDid[iloop].DDDIDNumOfElements >=
              Dcm_DspCfg.pDcmDspDidInfo[Dcm_DspCfg.pDcmDspDid[DidCfgIndex].DcmDspDidInfoIndex].
              DcmDspDDDIDMaxElements)
            {
                /*[SWS_Dcm_00861]over DcmDspDDDIDMaxElements,send NRC 0x31*/
                (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_REQUESTOUTOFRANGE);
                DsdInternal_ProcessingDone(ProtocolCtrlId);
                return  E_NOT_OK;
            }
            else
            {
                if (Subfunction == DCM_UDS0X2C_01_DDBYDID)
                {
                    for(Cnt = 0u;Cnt < RequestNum;Cnt++)
                    {
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                         Subfunction = Subfunction;
                        MemoryAddress = 0;
                        MemoryAddress = MemoryAddress | ((uint32)(Dcm_MsgCtrl[MsgCtrlId].
                                MsgContext.pReqData[4u + (Cnt * (3u))]) & 0xFFu);
                        MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].
                                MsgContext.pReqData[5u + (Cnt * (3u))]) & 0xFFUL) << 8u);
                        MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].
                                MsgContext.pReqData[6u + (Cnt * (3u))]) & 0xFFUL) << 16u);
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                        Data = MemoryAddress;
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                        Size = (uint16)((uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[7u + (Cnt * (3u))]) & 0xFFu;
                        Dcm_DDDid[iloop].DDDIDNumOfElements++;
                    }
                }
                else if (Subfunction == DCM_UDS0X2C_02_DDBYMEMORY)
                {
                    for(Cnt = 0u;Cnt < RequestNum;Cnt++)
                    {
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                        Subfunction = Subfunction;
                        /*caculate the MemoryAddress of the request message*/
                        MemoryAddress = 0;
                        for(index = 0u;index < memoryAddressByteLength;index++)
                        {
                            MemoryAddress = MemoryAddress << 8u;
                            MemoryAddress = MemoryAddress | ((uint32)(Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[5u
                                         + index + (Cnt * (memorySizeByteLength + memoryAddressByteLength))]) & 0xFFu);
                        }
                        Memorysize = 0;
                        for(index = 0u;index < memorySizeByteLength;index++)
                        {
                            Memorysize = Memorysize << 8u;
                            Memorysize = Memorysize | ((uint32)(Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                                    pReqData[5u + memoryAddressByteLength
                                         + index + (Cnt * (memorySizeByteLength + memoryAddressByteLength))]) & 0xFFu);
                        }
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                        Data = MemoryAddress;
                        Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                        Size = (uint16)Memorysize;
                        Dcm_DDDid[iloop].DDDIDNumOfElements++;
                    }
                }
                else if (Subfunction == DCM_UDS0X2C_03_CLEARDDDID)
                {
                    Dcm_DDDid[iloop].DDDid = 0u;/*clear DDDID*/
                    Dcm_DDDid[iloop].DDDIDNumOfElements = 0;
                }
                else
                {
                    /*idle*/
                }
            }
        }
    }
    else
    {
        if(Dcm_DDDid[iloop].DDDIDNumOfElements >=
          Dcm_DspCfg.pDcmDspDidInfo[Dcm_DspCfg.pDcmDspDid[DidCfgIndex].DcmDspDidInfoIndex].
          DcmDspDDDIDMaxElements)
        {
            /*[SWS_Dcm_00861]over DcmDspDDDIDMaxElements,send NRC 0x31*/
            (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_REQUESTOUTOFRANGE);
            DsdInternal_ProcessingDone(ProtocolCtrlId);
            return  E_NOT_OK;
        }
        else
        {
            if (Subfunction == DCM_UDS0X2C_01_DDBYDID)
            {
                for(Cnt = 0u;Cnt < RequestNum;Cnt++)
                {
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Subfunction = Subfunction;
                    MemoryAddress = 0;
                    MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                            pReqData[4u + (Cnt * (3u))]) & 0xFFUL));
                    MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                            pReqData[5u + (Cnt * (3u))]) & 0xFFUL) << 8u);
                    MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                            pReqData[6u + (Cnt * (3u))]) & 0xFFUL) << 16u);
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Data = MemoryAddress;
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Size = (uint16)((uint16)((uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[7u + (Cnt * (3u))]) & 0xFFu);
                    Dcm_DDDid[iloop].DDDIDNumOfElements++;
                }
            }
            else if (Subfunction == DCM_UDS0X2C_02_DDBYMEMORY)
            {
                for(Cnt = 0u;Cnt < RequestNum;Cnt++)
                {
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Subfunction = Subfunction;
                    /*caculate the MemoryAddress of the request message*/
                    MemoryAddress = 0;
                    for(index = 0u;index < memoryAddressByteLength;index++)
                    {
                        MemoryAddress = MemoryAddress << 8u;
                        MemoryAddress = MemoryAddress | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                                pReqData[5u + index +
                                        (Cnt * (memorySizeByteLength + memoryAddressByteLength))]) & 0xFFUL));
                    }
                    Memorysize = 0;
                    for(index = 0u;index < memorySizeByteLength;index++)
                    {
                        Memorysize = Memorysize << 8u;
                        Memorysize = Memorysize | (uint32)((uint32)(((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                                pReqData[5u + memoryAddressByteLength + index
                                     + (Cnt * (memorySizeByteLength + memoryAddressByteLength))]) & 0xFFUL));
                    }
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Data = MemoryAddress;
                    Dcm_DDDid[iloop].DcmDspAlternativeArgumentData[Dcm_DDDid[iloop].DDDIDNumOfElements].
                    Size = (uint16)Memorysize;
                    Dcm_DDDid[iloop].DDDIDNumOfElements++;
                }
            }
            else
            {
                /*idle*/
            }
        }
    }

    /*assemble and send positive response*/
    TxChannelCtrlIndex = Dcm_MsgCtrl[MsgCtrlId].Dcm_TxCtrlChannelIndex;
    TxChannelCfgIndex = Dcm_ChannelCtrl[TxChannelCtrlIndex].Dcm_ChannelCfgIndex;
    Offset = (Dcm_DslCfg.pDcmChannelCfg)[TxChannelCfgIndex].offset;

    /* check tx data length */
    if((4u) > (Dcm_DslCfg.pDcmChannelCfg[TxChannelCfgIndex].Dcm_DslBufferSize))
    {
        /*Pdu length is bigger than buffer size,ignore the request message */
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_RESPONSETOOLONG);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    Dcm_Channel[Offset] = 0x6C;
    Dcm_Channel[Offset + 1u] = Subfunction;
    Dcm_Channel[Offset + 2u] = (uint8)(RecDid>>8u);
    Dcm_Channel[Offset + 3u] = (uint8)RecDid;
    SchM_Enter_Dcm(Dcm_MsgCtrl);
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResMaxDataLen = 4u;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResDataLen    = 4u;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.pResData      = &Dcm_Channel[Offset];
    SchM_Exit_Dcm(Dcm_MsgCtrl);
    DsdInternal_ProcessingDone(ProtocolCtrlId);
#endif
#if((NVM_ENABLE == STD_ON) && ((DCM_DDDID_STORAGE == STD_ON) && (DCM_DSP_DDDID_MAX_NUMBER > 0)))
    (void)NvM_WriteBlock(DCM_DDDID_STORAGE_BLOCKID, &Dcm_DDDid);
#endif
    return  E_OK;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"
#endif

